package com.wgke.bluetooth.vm;

import static java.nio.charset.StandardCharsets.UTF_8;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.text.TextUtils;
import android.util.Log;

import androidx.lifecycle.MutableLiveData;

import com.google.gson.Gson;
import com.wgke.bluetooth.beans.CmdInfoBean;
import com.wgke.bluetooth.db.CmdEntity;
import com.wgke.bluetooth.tools.BtMsg;
import com.wgke.bluetooth.utils.Async;
import com.wgke.bluetooth.utils.BluetoothGattManager;
import com.wgke.bluetooth.utils.CommonUtil;
import com.wgke.bluetooth.utils.FileUtil;
import com.wgke.bluetooth.utils.LogUtil;
import com.wgke.bluetooth.utils.SpUtil;
import com.wgke.bluetooth.utils.ToastUtil;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;

public class ReadWriteVM extends BaseVM {

    public MutableLiveData<String> content = new MutableLiveData<>("");
    public MutableLiveData<Integer> readCount = new MutableLiveData<>(0);
    public MutableLiveData<List<CmdEntity>> list = new MutableLiveData<>();
    BluetoothGattCharacteristic write = null;
    BluetoothGattCharacteristic notice = null;

    private BluetoothGattManager bgm;

    private BluetoothGattManager getBgm() {
        if (bgm == null) {
            bgm = BluetoothGattManager.getInstance();
        }
        return bgm;
    }

    private boolean checkService() {
        if (null == getBgm().getGatt()) {
            Log.e("ReadWriteVM", "scanService: gatt is null");
            ToastUtil.showMsg("gatt 获取失败");
            return false;
        }
        if (null == getBgm().getServices()) {
            Log.e("ReadWriteVM", "scanService: services is null");
            ToastUtil.showMsg("services 获取失败");
            return false;
        }

        return true;
    }

    @SuppressLint("MissingPermission")
    public void readByService(String uuid) {
        if (!checkService()) {
            return;
        }
        BluetoothGattService service = getBgm().getService(uuid);
        if (null == service) {
            Log.e("ReadWriteVM", "service: gatt is null");
            ToastUtil.showMsg("services 查询失败");
            return;
        }

        List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
        BluetoothGattCharacteristic read = null;
        for (BluetoothGattCharacteristic characteristic : characteristics) {
            int properties = characteristic.getProperties();
            if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                // 可读特征
                read = characteristic;
            }
            if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                // 可写特征
                write = characteristic;
            } else if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
                if (write == null) write = characteristic;
            }
            if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                notice = characteristic;

            }
        }
        Log.e("ReadWriteVM", "read: " + (read != null) + ";write:" + (write != null) + ";notice: " + (notice != null));

        BluetoothGatt gatt = getBgm().getGatt();
        if (read != null) {
            boolean success = gatt.readCharacteristic(read);
            if (!success) {
                ToastUtil.showMsg("读取失败！");
            }
        } else {
            ToastUtil.showMsg("未发现 读取服务");
        }
    }

    int count = 0;

    /**
     * 读取 数字，用16进制显示
     */
    public void readBytes(boolean isRead, byte[] data) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : data) {
            hexString.append(String.format("%02X ", b));
        }
        Log.e("ReadWriteVM", "readBytes: " + hexString);
        count++;
        if (count > 99) {
            count = 1;
        }
        String showCount = count > 9 ? "" + count : "0" + count;
        if (SpUtil.getUseParse()) {
            byte[] newData = Arrays.copyOfRange(data, 2, data.length);
            if (cmdInfoBeans != null) {
                content.setValue("刷新" + showCount + "> " + parseDataToInfo(newData, cmdInfoBeans));
                return;
            }
        }
        content.setValue("刷新次数" + showCount + ">    " + hexString);
        // }
    }

    public void writeBytes(byte[] data) {
        if (!checkService()) {
            Log.e("ReadWriteVM", "writeBytes: return");
        } else if (null == write) {
            Log.e("ReadWriteVM", "writeBytes: write is null");
        } else {
            write.setValue(data);
            int writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
            write.setWriteType(writeType);
            // 执行写入操作
            @SuppressLint("MissingPermission") boolean success = getBgm().getGatt().writeCharacteristic(write);
            if (!success) {
                Log.e("ReadWriteVM", "写入请求发送失败");
                ToastUtil.showLongMsg("写入请求发送失败");
            }
            LogUtil.saveLog("send cmd " + success, data);
            return;
        }
        ToastUtil.showLongMsg("未找到 写入 特征值");
    }


    @SuppressLint("MissingPermission")
    public void setNotice(boolean isNotice) {
        if (!checkService()) {
            Log.e("ReadWriteVM", "setNotice:   is null");
        } else if (null == notice) {
            Log.e("ReadWriteVM", "scanService: services is null");
        } else {

            Log.e("ReadWriteVM", "wait notice");
            BluetoothGatt gatt = getBgm().getGatt();
            gatt.setCharacteristicNotification(notice, isNotice);
            BluetoothGattDescriptor descriptor = notice.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
            if (descriptor != null) {
                if (isNotice) {
                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                } else {
                    descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                }
                gatt.writeDescriptor(descriptor);
            }
            return;
        }
        if (!isNotice) return;
        ToastUtil.showLongMsg("未找到 通知 特征值");
    }

    public void loadCmdList() {
        Async.getInstance().await(() -> {
            try {
                list.postValue(Async.getInstance().getDao().getAll());
                String json = FileUtil.loadJsFromAssets("parseCmdinfo.json");
                cmdInfoBeans = CommonUtil.parseJsonArray(json, CmdInfoBean.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    public String changeCmd(String newCmd) {
        String cmd = newCmd.replace(" ", "");
        if (cmd.length() > 14 && cmd.length() % 2 == 0 && cmd.startsWith("ACAC")) {
            String bodyStr = cmd.substring(8);
            String cmdCode = bodyStr.substring(4, 6);
            LogUtil.d("changeCrc", "cmdCode=" + cmdCode);
            if ("27".equals(cmdCode)||"90".equals(cmdCode)) {
                LogUtil.d("changeCrc", "bodyStr=" + bodyStr + ";cmdCode=" + cmdCode);

                byte[] bytes = BtMsg.hexStringToByteArray(bodyStr);
                if (bodyStr.length() == 24) {
                    LogUtil.d("changeCrc", "add one bytes");
                    bytes = BtMsg.hexStringToByteArray(bodyStr + "00");
                    bytes[3]= (byte) (bytes[3]+1);
                }
                //ACAC 31A1 0102 27 1000 E907 07170C3609
                int size = bytes.length;
                //1000 E907 07 15 10 2B 1A
                Calendar calendar = Calendar.getInstance();
                int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始，所以要加1
                int day = calendar.get(Calendar.DAY_OF_MONTH);
                int hour = calendar.get(Calendar.HOUR_OF_DAY); // 24小时制
                int minute = calendar.get(Calendar.MINUTE);
                int second = calendar.get(Calendar.SECOND);
                int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
                bytes[size - 1] = (byte) second;
                bytes[size - 2] = (byte) minute;
                bytes[size - 3] = (byte) hour;
                bytes[size - 4] = (byte) dayOfWeek;
                bytes[size - 5] = (byte) day;
                bytes[size - 6] = (byte) month;
                LogUtil.d("changeCrc", new Gson().toJson(bytes));
                String bodyHex = BtMsg.byteArrayToHexString(bytes);
                LogUtil.d("changeCrc", bodyHex);
                byte[] crc = getCRC(bytes);
                LogUtil.d("changeCrc", "crc=" + bytesToHex(crc));
                return "ACAC" + bytesToHex(crc) + bodyHex;
            }
        }
        return newCmd;
    }

    public String changeCrc(String str) {
        if (str.length() > 8 && str.length() % 2 == 0 && str.startsWith("ACAC")) {
            String bodyStr = str.substring(8);
            LogUtil.d("changeCrc", "bodyStr=" + bodyStr);
            byte[] bytes = BtMsg.hexStringToByteArray(bodyStr);
            System.out.println(new Gson().toJson(bytes));
            byte[] crc = getCRC(bytes);
            LogUtil.d("changeCrc", "crc=" + bytesToHex(crc));
            return "ACAC" + bytesToHex(crc) + bodyStr;
        }
        return "";
    }

    private byte[] getCRC(byte[] buf) {
        int crc = 0xFFFF;
        for (byte b : buf) {
            crc ^= (b & 0xFF);
            for (int i = 0; i < 8; i++) {
                if ((crc & 1) != 0) {
                    crc >>= 1;
                    crc ^= 0xA001;
                } else {
                    crc >>= 1;
                }
            }
        }
        // 输出CRC值用于调试
        System.out.println("runSingleDeviceCmd-crc: " + crc);
        // 将CRC值转换为字节数组(低字节在前)
        return new byte[]{(byte) (crc & 0xFF), (byte) ((crc >> 8) & 0xFF)};
    }

    public String bytesToHex(byte[] bytes) {
        StringBuilder hexBuilder = new StringBuilder();
        for (byte b : bytes) {
            // 方法1：使用 String.format（推荐）
            hexBuilder.append(String.format("%02X", b));
        }
        return hexBuilder.toString();
    }

    private List<CmdInfoBean> cmdInfoBeans;

    /**
     * 解析数据
     */
    public static String parseDataToInfo(byte[] data, List<CmdInfoBean> cmdInfoBeans) {
        StringBuilder sb = new StringBuilder();
        List<CmdInfoBean> second = null;
        if (data == null && data.length < 2) return "";
        for (int i = 0; i < 2; i++) {
            byte v = data[i];
            for (CmdInfoBean b : cmdInfoBeans) {
                if (b.position == i) {
                    if (b.params != null) {
                        for (CmdInfoBean b2 : b.params) {
                            Log.e("Actions", "b2.name=" + b2.name + " b2.value=" + b2.value + " v=" + v);
                            if (b2.value == v) {
                                second = b2.params;
                                sb.append(b2.name + ":" + v + ";");
                            }
                        }
                    } else {
                        sb.append(b.name + ":" + v + ";");

                    }
                }
            }
        }
        if (second == null) {
            Log.e("Actions", "second is null");
            return sb.toString();
        }
        sb.append("\n");
        for (int i = 2; i < data.length; i++) {
            for (CmdInfoBean b : second) {
                if (b.position == i) {
                    if (b.params != null) {
                        String temp = "";
                        for (CmdInfoBean b2 : b.params) {
                            if (b2.value == data[i]) {
                                temp = b.name + ":" + b2.name + ";";
                            }
                        }
                        if (TextUtils.isEmpty(temp)) {
                            sb.append(b.name + ":不能识别;\n");
                        } else {
                            sb.append(temp + "\n");
                        }
                    } else {
                        if (b.length == 2) {
                            int v = data[i];
                            if (data.length > i + 1) {
                                v = v + 256 * data[i + 1];
                            }
                            sb.append(b.name + ":" + v + ";\n");
                        } else {
                            sb.append(b.name + ":" + data[i] + ";\n");
                        }
                    }
                }
            }
        }
        return sb.toString();
    }
}
